// copyright jyz.2024


#include "AuraAttributeSet.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "AuraGameplayTags.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectExtension.h"
#include "Data/AuraAttributeInfo.h"
#include "GameFramework/Character.h"
#include "Interaction/CombatInterface.h"
#include "Player/AuraPlayerController.h"

#define BindVitalAttribute(ASName) FAttributeSignature ASName##Delegate;\
		ASName##Delegate.BindStatic(Get##ASName##Attribute);\
		AttributeDelegateMap.Add(GameplayTags.AS_Vital_##ASName,ASName##Delegate)

#define BindPrimayAttribute(ASName) FAttributeSignature ASName##Delegate;\
		ASName##Delegate.BindStatic(Get##ASName##Attribute);\
		AttributeDelegateMap.Add(GameplayTags.AS_Primary_##ASName,ASName##Delegate)

#define BindSecondaryAttribute(ASName) FAttributeSignature ASName##Delegate;\
		ASName##Delegate.BindStatic(Get##ASName##Attribute);\
		AttributeDelegateMap.Add(GameplayTags.AS_Sec_##ASName,ASName##Delegate)
UAuraAttributeSet::UAuraAttributeSet()
{
	 //InitHealth(50.f);
	// InitMaxHealth(100.f);
	 //InitMana(10.f);
	// InitMaxMana(50.f);
	const FAuraGameplayTags& GameplayTags = FAuraGameplayTags::Get();

	AttributeDelegateMap.Add(GameplayTags.AS_Vital_Health,GetHealthAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Vital_Mana,GetManaAttribute);

	
	AttributeDelegateMap.Add(GameplayTags.AS_Primary_Strength,GetStrengthAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Primary_Intelligence,GetIntelligenceAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Primary_Resilience,GetResilienceAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Primary_Vigor,GetVigorAttribute);

	AttributeDelegateMap.Add(GameplayTags.AS_Sec_Armor,GetArmorAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_ArmorPiercing,GetArmorPiercingAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_BlockChance,GetBlockChanceAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_CriticalChance,GetCriticalChanceAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_CriticalDamage,GetCriticalDamageAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_CriticalHitResistance,GetCriticalHitResistanceAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_HealthRegeneration,GetHealthRegenerationAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_ManaRegeneration,GetManaRegenerationAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_MaxHealth,GetMaxHealthAttribute);
	AttributeDelegateMap.Add(GameplayTags.AS_Sec_MaxMana,GetMaxManaAttribute);
	//Vital Attributes（至关重要的）
	// BindVitalAttribute(Health);
	// BindVitalAttribute(Mana);
	//
	// //绑定重要的属性
	// BindPrimayAttribute(Strength);
	// BindPrimayAttribute(Intelligence);
	// BindPrimayAttribute(Resilience);
	// BindPrimayAttribute(Vigor);
	//
	// //绑定次要的属性
	// BindSecondaryAttribute(Armor);
	// BindSecondaryAttribute(ArmorPiercing);
	// BindSecondaryAttribute(BlockChance);
	// BindSecondaryAttribute(CriticalChance);
	// BindSecondaryAttribute(CriticalDamage);
	// BindSecondaryAttribute(CriticalHitResistance);
	// BindSecondaryAttribute(HealthRegeneration);
	// BindSecondaryAttribute(ManaRegeneration);
	// BindSecondaryAttribute(MaxHealth);
	// BindSecondaryAttribute(MaxMana);

	
}

void UAuraAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	//Primary Attributes(主要的)
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Strength, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Intelligence, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Resilience, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Vigor, COND_None, REPNOTIFY_Always);

	//Vital Attributes（至关重要的）
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Health, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Mana, COND_None, REPNOTIFY_Always);


	//次要属性（依赖主要属性）--->Secondary Attributes
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Armor, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, ArmorPiercing, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, BlockChance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalChance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalDamage, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalHitResistance, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, HealthRegeneration, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, ManaRegeneration, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);
}

void UAuraAttributeSet::PreAttributeBaseChange(const FGameplayAttribute& Attribute, float& NewValue) const
{
	Super::PreAttributeBaseChange(Attribute, NewValue);
	if (Attribute == GetHealthAttribute())
	{
		NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
	}
	if (Attribute == GetMaxHealthAttribute())
	{
		//UE_LOG(LogTemp,Warning,TEXT("MaxHealth:%f"),NewValue);
	}
	if (Attribute == GetManaAttribute())
	{
		NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());
		//UE_LOG(LogTemp,Warning,TEXT("Mana:%f"),NewValue);
	}
	if (Attribute == GetMaxManaAttribute())
	{
		//UE_LOG(LogTemp,Warning,TEXT("MaxMana:%f"),NewValue);
	}
}

void UAuraAttributeSet::SetEffectProperties(
	const FGameplayEffectModCallbackData& Data,
	FEffectProperties& SourceProps,
	FEffectProperties& TargetProps) const
{
	//EffectContextHandle.GetInstigatorAbilitySystemComponent(): 的解释 --->核心：GetInstigator将指向玩家B（当前调用者）
	//此函数返回当前调用者的AbilitySystemComponent。
	//此组件代表当前触发效果或能力的实体，
	//这可能是一个中间实体在因果链中。
	//例如，如果玩家A使玩家B受到一个链接到玩家C的buff，那么GetInstigator将指向玩家B，而GetOriginalInstigator将指向玩家A。

	//为了更具象，让我们设想这样一个场景：
	//你的游戏角色（称为角色A）对一个怪兽（具有特殊能力，当受到攻击时可以反弹攻击给攻击者）进行了攻击并触发了一个燃烧效果。
	//这个效果又对另一名游戏角色（称为角色B）造成了伤害。
	//那么在这个场景中，尽管角色B受到了效果，但是角色A是原始引起效果的实体。
	//即角色A的AbilitySystemComponent会被GetOriginalInstigatorAbilitySystemComponent这个函数返回。
	SourceProps.AbilitySystemComponent = EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent();
	if (IsValid(SourceProps.AbilitySystemComponent) &&
		SourceProps.AbilitySystemComponent->AbilityActorInfo.IsValid() &&
		SourceProps.AbilitySystemComponent->AbilityActorInfo->AvatarActor.IsValid())
	{
		SourceProps.AvatarActor = SourceProps.AbilitySystemComponent->AbilityActorInfo->AvatarActor.Get();
		SourceProps.Controller = SourceProps.AbilitySystemComponent->AbilityActorInfo->PlayerController.Get();
		if (SourceProps.Controller == nullptr && SourceProps.AbilitySystemComponent != nullptr)
		{
			if (const APawn* Pawn = Cast<APawn>(SourceProps.AvatarActor))
			{
				SourceProps.Controller = Pawn->GetController();
			}
		}
		if (SourceProps.Controller)
		{
			SourceProps.Character = Cast<ACharacter>(SourceProps.Controller->GetPawn());
		}
	}
	if (Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid())
	{
		TargetProps.AvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();
		TargetProps.Controller = Data.Target.AbilityActorInfo->PlayerController.Get();
		TargetProps.Character = Cast<ACharacter>(TargetProps.AvatarActor);
		TargetProps.AbilitySystemComponent = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetProps.AvatarActor);
	}
}

void UAuraAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
	Super::PostGameplayEffectExecute(Data);
	// if(Data.EvaluatedData.Attribute==GetHealthAttribute())
	// {
	// 	//UE_LOG(LogTemp,Warning,TEXT("Health:%f"),GetHealth());
	// 	//修改幅度 比如说血量+1 -25这样的修改幅度
	// 	//UE_LOG(LogTemp,Warning,TEXT("Magnitude:%f"),Data.EvaluatedData.Magnitude);
	// 	SetHealth(FMath::Clamp(GetHealth(),0,GetMaxHealth()));
	// }
	FEffectProperties SourceProps;
	FEffectProperties TargetProps;
	EffectContextHandle = Data.EffectSpec.GetContext();
	SetEffectProperties(Data, SourceProps, TargetProps);
	if(Data.EvaluatedData.Attribute == GetIncomingDamageAttribute())
	{
		const float LocalIncomingDamage = GetIncomingDamage();
		SetIncomingDamage(0.f);
		if(LocalIncomingDamage>0.f)
		{
			const float NewHealth = GetHealth() - LocalIncomingDamage;
			SetHealth(FMath::Clamp(NewHealth,0,GetMaxHealth()));
			const float bFatal = NewHealth <= 0.f;
			if(!bFatal)
			{
				//扣血但是没死，角色尝试激活带有Effects_HitReact标签的能力（表现为受击）
				FGameplayTagContainer TagContainer;
				TagContainer.AddTag(FAuraGameplayTags::Get().Effects_HitReact);
				TargetProps.AbilitySystemComponent->TryActivateAbilitiesByTag(TagContainer);
			}
			else
			{
				ICombatInterface* CombatInterface = CastChecked<ICombatInterface>(TargetProps.AvatarActor);
				CombatInterface->Die();
			}
			if(SourceProps.Character!=TargetProps.Character)
			{
				if(AAuraPlayerController* PC = Cast<AAuraPlayerController>(SourceProps.Controller))
				{
					PC->ShowDamageNumber(LocalIncomingDamage,TargetProps.Character);
				}
			}
		}
	}
}

void UAuraAttributeSet::OnRep_Strength(const FGameplayAttributeData& OldStrength) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Strength, OldStrength);
}

void UAuraAttributeSet::OnRep_Intelligence(const FGameplayAttributeData& OldIntelligence) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Intelligence, OldIntelligence);
}

void UAuraAttributeSet::OnRep_Resilience(const FGameplayAttributeData& OldResilience) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Resilience, OldResilience);
}

void UAuraAttributeSet::OnRep_Vigor(const FGameplayAttributeData& OldVigor) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Vigor, OldVigor);
}

void UAuraAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Health, OldHealth);
}

void UAuraAttributeSet::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, MaxHealth, OldMaxHealth);
}

void UAuraAttributeSet::OnRep_Mana(const FGameplayAttributeData& OldMana) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Mana, OldMana);
}

void UAuraAttributeSet::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, MaxMana, OldMaxMana);
}

void UAuraAttributeSet::OnRep_Armor(const FGameplayAttributeData& OldArmor) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Armor, OldArmor);
}

void UAuraAttributeSet::OnRep_ArmorPiercing(const FGameplayAttributeData& OldArmorPiercing) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, ArmorPiercing, OldArmorPiercing);
}

void UAuraAttributeSet::OnRep_BlockChance(const FGameplayAttributeData& OldBlockChance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, BlockChance, OldBlockChance);
}

void UAuraAttributeSet::OnRep_CriticalChance(const FGameplayAttributeData& OldCriticalChance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalChance, OldCriticalChance);
}

void UAuraAttributeSet::OnRep_CriticalDamage(const FGameplayAttributeData& OldCriticalDamage) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalDamage, OldCriticalDamage);
}

void UAuraAttributeSet::OnRep_CriticalHitResistance(const FGameplayAttributeData& OldCriticalHitResistance) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalHitResistance, OldCriticalHitResistance);
}

void UAuraAttributeSet::OnRep_HealthRegeneration(const FGameplayAttributeData& OldHealthRegeneration) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, HealthRegeneration, OldHealthRegeneration);
}

void UAuraAttributeSet::OnRep_ManaRegeneration(const FGameplayAttributeData& OldArmorPiercing) const
{
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, ArmorPiercing, OldArmorPiercing);
}
#undef BindVitalAttribute
#undef BindPrimayAttribute
#undef BindSecondaryAttribute